// 版权所有（c）2019 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package edwards25519

import (
	"crypto/subtle"
)

// 用于可变基、恒定时间标量MUL的动态查找表。
type projLookupTable struct {
	points [8]projCached
}

// 固定基、恒定时间标量MUL的预计算查找表。
type affineLookupTable struct {
	points [8]affineCached
}

// 用于可变基、可变时间标量MUL的动态查找表。
type nafLookupTable5 struct {
	points [8]projCached
}

// 固定基、可变时间标量MUL的预计算查找表。
type nafLookupTable8 struct {
	points [64]affineCached
}

// 构造器。

// 在运行时生成查找表。快速的
func (v *projLookupTable) FromP3(q *Point) {
	// 目标：分数[i]=（i+1）*Q，即Q，2Q，…，8Q
	// 这允许查找-8Q，…-Q，0，Q，…，8Q
	v.points[0].FromP3(q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		// 将（i+1）*Q计算为Q+i*Q，并将其转换为已计算的方法
		// 这是不必要的复杂，因为API有显式的
		// 接收，而不是创建堆栈对象并依赖RVO
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
	}
}

// 这不是针对速度的优化；应预计算固定基表。
func (v *affineLookupTable) FromP3(q *Point) {
	// 目标：分数[i]=（i+1）*Q，即Q，2Q，…，8Q
	// 这允许查找-8Q，…-Q，0，Q，…，8Q
	v.points[0].FromP3(q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		// 将（i+1）*Q计算为Q+i*Q并转换为仿射
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
	}
}

// 在运行时生成查找表。快速的
func (v *nafLookupTable5) FromP3(q *Point) {
	// 目标：v点[i]=（2*i+1）*Q，即Q、3Q、5Q、…、15Q
	// 这允许查找-15Q、-3Q、-Q、0、Q、3Q、…、15Q
	v.points[0].FromP3(q)
	q2 := Point{}
	q2.Add(q, q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 7; i++ {
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
	}
}

// 这不是针对速度的优化；应预计算固定基表。
func (v *nafLookupTable8) FromP3(q *Point) {
	v.points[0].FromP3(q)
	q2 := Point{}
	q2.Add(q, q)
	tmpP3 := Point{}
	tmpP1xP1 := projP1xP1{}
	for i := 0; i < 63; i++ {
		v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
	}
}

// 选择器。

// 将dest设置为x*Q，其中-8<=x<=8，时间不变。
func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
	// 计算xabs=| x|
	xmask := x >> 7
	xabs := uint8((x + xmask) ^ xmask)

	dest.Zero()
	for j := 1; j <= 8; j++ {
		// 如果| x |=j，则设置dest=j*Q
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
		dest.Select(&v.points[j-1], dest, cond)
	}
	// 现在dest=|x |*Q，条件否定得到x*Q
	dest.CondNeg(int(xmask & 1))
}

// 将dest设置为x*Q，其中-8<=x<=8，时间不变。
func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
	// 计算xabs=| x|
	xmask := x >> 7
	xabs := uint8((x + xmask) ^ xmask)

	dest.Zero()
	for j := 1; j <= 8; j++ {
		// 如果| x |=j，则设置dest=j*Q
		cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
		dest.Select(&v.points[j-1], dest, cond)
	}
	// 现在dest=|x |*Q，条件否定得到x*Q
	dest.CondNeg(int(xmask & 1))
}

// 给定0<x<2^4的奇数x，返回x*Q（在可变时间内）。
func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
	*dest = v.points[x/2]
}

// 给定0<x<2^7的奇数x，返回x*Q（在可变时间内）。
func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
	*dest = v.points[x/2]
}
